package com.example.base.task

import kotlinx.coroutines.*
import java.util.concurrent.CancellationException
import kotlin.jvm.Throws

/**
 * 带结果的任务
 */
open class SingleTask<RESULT> : ITask {

    private var successAction: ((RESULT) -> Unit)? = null
    private var errorAction: ((Throwable) -> Unit)? = null
    private var beforeAction: (() -> Unit)? = null
    private var interruptedAction: (() -> Unit)? = null

    private val mainDispatcher = if (Task.ANDROID_PLATFORM) Dispatchers.Main else Dispatchers.Default

    private var isSuccess: Boolean = false
    private var hasError = false
    private var running = false
    var isCancelled: Boolean = false
        private set

    val isRunning: Boolean
        get() = job != null && !job!!.isCancelled && running && !isCancelled

    private var job: Job? = null


    /**
     * 启动任务
     */
    fun start(): SingleTask<RESULT> {
        job?.cancel()
        job = GlobalScope.launch(start = CoroutineStart.LAZY, context = Dispatchers.Default) {
            runCatching {
                if (isRunning)
                    throw IllegalStateException("already started")

                hasError = false
                isCancelled = false
                isSuccess = false
                running = true

                // BEFORE
                launch(mainDispatcher) {
                    onTaskBefore()
                    beforeAction?.invoke()
                }

                if (isCancelled)
                    throw RuntimeException("task is already cancelled")
                return@runCatching onTaskRun()
            }.onSuccess { result ->
                launch(mainDispatcher) {
                    running = false
                    isSuccess = true
                    onTaskSuccess(result)
                    successAction?.invoke(result)
                }
            }.onFailure { error ->
                launch(mainDispatcher) {
                    when(error) {
                        is CancellationException -> {
                            onTaskInterrupted()
                            interruptedAction?.invoke()
                        }
                        else -> {
                            running = false
                            isSuccess = false
                            hasError = true
                            onTaskError(error)
                            errorAction?.invoke(error)
                        }
                    }
                }
            }
        }
        job?.start()
        return this
    }

    /**
     * 主动中断任务
     */
    fun cancel() {
        isCancelled = true
        job?.cancel()
        job = null
    }

    /**
     * 事件：执行前
     */
    fun before(action: () -> Unit): SingleTask<RESULT> {
        beforeAction = action
        return this
    }

    /**
     * 事件：任务成功
     */
    fun success(action: (RESULT) -> Unit): SingleTask<RESULT> {
        successAction = action
        return this
    }

    /**
     * 事件：任务出错
     */
    fun error(action: (Throwable) -> Unit): SingleTask<RESULT> {
        errorAction = action
        return this
    }

    /**
     * 事件：主动中断
     */
    fun interrupted(action: () -> Unit): SingleTask<RESULT> {
        interruptedAction = action
        return this
    }

    protected fun onTaskBefore() {}

    /**
     * 任务执行信息，如果继承SingleTask，则重构此方法
     */
    @Throws(Exception::class)
    protected open suspend fun onTaskRun(): RESULT {
        throw NotImplementedError()
    }

    protected fun onTaskSuccess(result: RESULT) {}

    protected fun onTaskError(error: Throwable) {}

    protected fun onTaskInterrupted() {}

    private var proxy = object : ITaskProxy {
        override fun start() {
            this@SingleTask.start()
        }

        override fun stop() {
            this@SingleTask.cancel()
        }
    }

    override fun getProxy(): ITaskProxy {
        return proxy
    }
}